/*
 * Checker.java
 *
 * Created on 10 październik 2007, 20:55
 *
 */

package kosciak.blip4j.automation;

import java.util.ArrayList;
import java.util.List;
import java.util.Timer;
import java.util.TimerTask;
import javax.swing.event.EventListenerList;
import kosciak.blip4j.*;

/**
 * <CODE>Checker</CODE> is an abstract class for all Update Checkers.
 * It checks periodically for new Updates and if find any fires Status and DirectMessage Events to registered UpdateEventListeners.
 * 
 * @author Wojtek 'KosciaK' Pietrzok
 * @since 0.1
 */
public abstract class Checker extends TimerTask{
    
    private EventListenerList listenerList;
    private BlipClient client;
    private int last;
    private long interval;
        
    /**
     * Creates a new instance of Checker
     */
    private Checker() {
        listenerList = new EventListenerList();
    }
    
    /**
     * Needs to be called by all subclasses.
     * @param client a BlipClient to be used by the Update Checker
     * @param start an Update to start checking from
     * @param interval an interval between checking (in miliseconds)
     */
    public Checker(BlipClient client, int start, long interval) {
        this();
        this.client = client;
        this.last = start;
        this.interval = interval;
    }

    /**
     * Checks periodically for new Updates.
     */
    @Override
    public final void run() {
        List<Update> updates = new ArrayList<Update>(1);
        try {
            updates = poll();
        } catch (BlipException ex) {
            ex.printStackTrace();
        }
        int size = updates.size();
        if (size > 0)
            last = updates.get(size - 1).getId();
        for(Update update : updates) {
            switch(update.getType()){
                case DirMsg :
                    fireDirectMessageEvent(new DirectMessageEvent(this, client, (DirectMessage) update));
                    break;
                case Status :
                    fireStatusEvent(new StatusEvent(this, client, (Status) update));
                    break;
            }
        }
    }
    
    /**
     * Polls the list of Updates.
     * This is an abstract method. Every Update Checker implementation has to implement it. It is called by run() method, if it returns non-empty list run() method will fire the Events.
     * 
     * You don't have to worry about BlipException - run() method treat it as if an empty List was returned.
     * 
     * Example:
     * <PRE>List&lt;Update&gt; poll() throws BlipException {
     *    getBlipClient().poll(getLast());
     * }</PRE>
     * @return a List of Updates
     * @throws kosciak.blip4j.BlipException if an error occurs
     */
    public abstract List<Update> poll() throws BlipException;

    /**
     * Gets an Id of last Update
     * @return an Id of last Update
     */
    protected final int getLast() {
        return last;
    }
    
    /**
     * Gets BlipClient used by this Update Checker
     * @return a BlipClient used by this Update Checker
     */
    protected final BlipClient getBlipClient() {
        return client;
    }
    
    /**
     * Adds UpdateEventListener
     * @param listener an UpdateEventListener to be added
     */
    public void addUpdateEventListener(UpdateEventListener listener) {
        listenerList.add(UpdateEventListener.class, listener);
    }
    
    /**
     * Removes UpdateEventListener
     * @param listener UpdateEventListener to be removed
     */
    public void removeUpdateListener(UpdateEventListener listener) {
        listenerList.remove(UpdateEventListener.class, listener);
    }

    private void fireStatusEvent(StatusEvent event) {
        UpdateEventListener[] listeners = listenerList.getListeners(UpdateEventListener.class);
        for(UpdateEventListener listener : listeners) {
            listener.processStatus(event);
        }
    }
    
    private void fireDirectMessageEvent(DirectMessageEvent event) {
        UpdateEventListener[] listeners = listenerList.getListeners(UpdateEventListener.class);
        for(UpdateEventListener listener : listeners) {
            listener.processDirectMessage(event);
        }
    }
 
}
